package com.jfinal.web.controller;

import com.jfinal.aop.Before;
import com.jfinal.common.Constants;
import com.jfinal.core.Controller;
import com.jfinal.ext.interceptor.NotAction;
import com.jfinal.i18n.I18n;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.QueryObject;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.render.PoiRender;
import com.jfinal.upload.UploadFile;
import com.jfinal.web.Response;
import com.jfinal.web.WebKit;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Pattern;

/**
 * 自定义的扩展controller，增加了一些便捷操作方法，使继承类代码更简
 *
 * @author CHEN
 */
public class BaseController extends Controller {

    /**
     * 获取查询对象
     *
     * @return
     */
    protected QueryObject getQueryObject() {

        QueryObject qo = new QueryObject();

        Map<String, String[]> map = getParaMap();
        for (Entry<String, String[]> entry : map.entrySet()) {
            qo.addParam(entry.getKey(), StrKit.join(entry.getValue()));
        }

        String requestBody = getRequestBody();
        if (!StrKit.isBlank(requestBody) && requestBody.trim().startsWith("{")) {
            Map<?, ?> map1 = JsonKit.parse(requestBody, Map.class);
            for (Entry<?, ?> entry : map1.entrySet()) {
                qo.addParam((String) entry.getKey(), entry.getValue());
            }
        }

        return qo;
    }

    /**
     * 参数不能为空
     *
     * @param para 参数名
     */
    protected void assertParaNotBlank(String para) {
        assertParaNotBlank(para, para + " 不能为空!");
    }

    /**
     * 参数不能为空
     *
     * @param para         参数名
     * @param errorMessage 错误信息
     * @return
     */
    protected void assertParaNotBlank(String para, String errorMessage) {
        if (isParaBlank(para)) {
            throw new IllegalArgumentException(errorMessage);
        }
    }

    /**
     * 设置当前登陆用户
     *
     * @param object
     */
    protected void setCurrentAccount(Object object, String sessionId, int maxAgeInSeconds) {
        setCookie(Constants.getCookieLoginKey(), sessionId, maxAgeInSeconds);
        setSessionAttr(Constants.getSessionLoginKey(), object);
        //删除子系统账号
        removeCurrentSysAccount();
    }

    /**
     * 获取当前登陆用户
     *
     * @param <T>
     * @return
     */
    public <T> T getCurrentAccount() {
        return getSessionAttr(Constants.getSessionLoginKey());
    }

    /**
     * 清除当前登陆用户
     *
     * @return
     */
    protected void removeCurrentAccount() {
        removeCookie(Constants.getCookieLoginKey());
        removeSessionAttr(Constants.getSessionLoginKey());
        //删除子系统账号
        removeCurrentSysAccount();
    }

    /**
     * 设置当前登陆系统用户
     *
     * @param object
     */
    protected void setCurrentSysAccount(Object object) {
        setSessionAttr(Constants.getSysName(), object);
    }

    public <T> T getCurrentSysAccount() {
        return getSessionAttr(Constants.getSysName());
    }

    /**
     * 清除当前登陆用户
     *
     * @return
     */
    protected void removeCurrentSysAccount() {
        removeSessionAttr(Constants.getSysName());
    }

    /**
     * 是否为POST请求
     *
     * @return
     */
    protected boolean isPostMethod() {
        return WebKit.isPostMethod(getRequest());
    }

    /**
     * 是否为GET请求
     *
     * @return
     */
    protected boolean isGetMethod() {
        return WebKit.isGetMethod(getRequest());
    }

    /**
     * 判断ajax请求
     *
     * @return
     */
    protected boolean isAjax() {
        Boolean isAjax = getParaToBoolean("ajax", false);
        return isAjax || WebKit.isAjax(getRequest());
    }

    /**
     * 获取payload
     * replace to getRequestBody
     *
     * @return
     */
    @Deprecated
    protected String getPayload() {
        try {
            return WebKit.getPayload(getRequest());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取payload
     *
     * @return
     */
    protected String getRequestBody() {
        return WebKit.getRequestBody(getRequest());
    }

    /**
     * 获取客户端真实ip，适用于使用了代理的情况
     *
     * @return
     */
    protected String getClientIp() {
        return WebKit.getClientIP(getRequest());
    }

    /**
     * 获取serverName，适用于代理的情况，包含端口号
     *
     * @return
     */
    protected String getServerName() {
        return WebKit.getServerName(getRequest());
    }

    /**
     * 获取访问url的前缀，从http://一直包含到contextPath
     *
     * @return
     */
    protected String getUrlPrefix() {
        return WebKit.getUrlPrefix(getRequest());
    }

    /**
     * 输出js
     *
     * @param jsContent
     */
    protected void renderJs(String jsContent) {
        renderHtml("<script type=\"text/javascript\">" + jsContent + "</script>");
    }

    protected void renderFailed(String message) {
        renderJson(Response.fail(message));
    }

    protected void renderFailed(int status, String message) {
        renderJson(Response.fail(message));
    }

    protected void renderFailed(Object data, String message) {
        renderJson(Response.fail(message).setData(data));
    }

    protected void renderFailed(String reqId, Object data) {
        renderJson(Response.fail().setReqId(reqId).setData(data));
    }

    protected void renderFailed(String reqId, Object data, String message) {
        renderJson(Response.fail(message).setReqId(reqId).setData(data));
    }


    protected void renderSuccess() {
        renderJson(Response.success());
    }

    protected void renderSuccess(String message) {
        renderJson(Response.success(message));
    }

    protected void renderSuccess(Object data) {
        renderJson(Response.success().setData(data));
    }

    protected void renderSuccess(Object data, String message) {
        renderJson(Response.success(message).setData(data));
    }

    protected void renderSuccess(String reqId, Object data) {
        renderJson(Response.success().setReqId(reqId).setData(data));
    }

    protected void renderSuccess(String reqId, Object data, String message) {
        renderJson(Response.success(message).setReqId(reqId).setData(data));
    }


    private List<?> getList(Page<?> page, List<String> columns) {
        List<?> rows = page.getList();
        if (!rows.isEmpty()) {
            //兼容Record类型
            if (rows.get(0) instanceof Record) {
                List<Map<String, Object>> tempList = new ArrayList<>(rows.size());
                for (Record record : (List<Record>) rows) {
                    Map<String, Object> recordMap = new HashMap<>();
                    if (columns == null) {
                        tempList.add(record.getColumns());
                    } else {
                        //只保留需要显示的字段
                        columns.forEach(column -> {
                            if (record.getColumns().keySet().contains(column)) {
                                recordMap.put(column, record.getColumns().get(column));
                            }
                        });
                        tempList.add(recordMap);
                    }

                }
                rows = tempList;
            }
        }
        return rows;
    }

    protected void renderJson(Page<?> page) {
        renderJson(page, null);
    }

    protected void renderJson(Page<?> page, List<String> columns) {
        Response response = Response.success();
        response.setData(Kv.create()
                .set("rows", getList(page, columns))
                .set("total", page.getTotalRow())
                .set("summary", page.getSummary()));
        renderJson(response);
    }

    protected void renderJson4Combo(List<Record> records) {
        List<Map<String, Object>> comboData = new ArrayList<>();
        for (Record record : records) {
            comboData.add(record.getColumns());
        }
        renderJson(comboData);
    }

    protected void renderJson(Ret ret) {
        Response response = ret.isOk() ? Response.success() : Response.fail();
        response.setData(ret);
        renderJson(response);
    }

    protected BigDecimal getParaToBigDecimal(String name) {
        return isParaBlank(name) ? null : new BigDecimal(getRequest().getParameter(name));
    }

    public void printRequest() {
        System.out.println(getRequest().getServletPath());
        System.out.println("PathInfo: " + getRequest().getPathInfo());
        System.out.println("QueryString: " + getRequest().getQueryString());
        System.out.println("RequestURI: " + getRequest().getRequestURI());
        System.out.println("RequestURL: " + getRequest().getRequestURL());
        System.out.println("ServletPath: " + getRequest().getServletPath());
        System.out.println("getContextPath: " + getRequest().getContextPath());
    }

    public void renderErrorPage(String message) {
        setAttr("message", message);
        render("/errorPage.html");
    }

    /**
     * Jsonp格式输出
     *
     * @param callback
     * @param result
     */
    protected void renderJsonp(String callback, Object result) {
        renderJson(callback + "(" + JsonKit.toJson(result) + ")");
    }

    protected void renderExcel(List list, String[] headerName, String[] headerKey, String fileName) {
        PoiRender.me(this.getResponse(), list).headers(headerName).columns(headerKey).fileName(fileName + ".xls").render();
    }

    private static Pattern idsParamPattern = Pattern.compile("[0-9]*");

    protected List<String> getIdsParam(String paramVal) {
        List<String> searchIds = new ArrayList<>();
        if (paramVal != null) {
            String[] paramArray = paramVal.split(",");
            if (paramVal != null && paramArray.length > 0) {
                for (String idStr : paramArray) {
                    if (idsParamPattern.matcher(idStr).matches()) {
                        searchIds.add(idStr);
                    }
                }
            }
        }
        return searchIds;
    }

    protected List<String> getStrsParam(String paramVal) {
        List<String> searchIds = new ArrayList<>();
        if (paramVal != null) {
            String[] paramArray = paramVal.split(",");
            if (paramVal != null && paramArray.length > 0) {
                for (String idStr : paramArray) {
                    searchIds.add("'" + idStr + "'");
                }
            }
        }
        return searchIds;
    }

    /**
     * 获取所有请求参数
     *
     * @return
     */
    protected Map<String, Object> getRequestParas() {
        Map<String, Object> params = new HashMap<>();
        Enumeration<String> paraNames = getParaNames();
        while (paraNames.hasMoreElements()) {
            String param = paraNames.nextElement();
            params.put(param, getPara(param));
        }
        return params;
    }

    protected void I18nRenderFailed(String key) {
        renderFailed(I18n.use().get(key));
    }

    protected void I18nRenderSuccess(String key) {
        renderSuccess(I18n.use().get(key));
    }


    /**
     * 是否是手机浏览器
     */
    protected boolean isMoblieBrowser() {
        return WebKit.isMoblieBrowser(getRequest());
    }

    /**
     * 是否是微信浏览器
     */
    protected boolean isWechatBrowser() {
        return WebKit.isWechatBrowser(getRequest());
    }

    /**
     * 是否是IE浏览器
     */
    protected boolean isIEBrowser() {
        return WebKit.isIEBrowser(getRequest());
    }

    /**
     * 是否是ajax请求
     */
    protected boolean isAjaxRequest() {
        return WebKit.isAjaxRequest(getRequest());
    }

    /**
     * 是否是multpart的请求（带有文件上传的请求）
     */
    protected boolean isMultipartRequest() {
        return WebKit.isMultipartRequest(getRequest());
    }


    /**
     * 获取ip地址
     */
    @Before (NotAction.class)
    protected String getIPAddress() {
        return WebKit.getIpAddress(getRequest());
    }

    /**
     * 获取 referer
     */
    @Before (NotAction.class)
    protected String getReferer() {
        return WebKit.getReferer(getRequest());
    }


    /**
     * 获取ua
     */
    @Before (NotAction.class)
    protected String getUserAgent() {
        return WebKit.getUserAgent(getRequest());
    }

    /**
     * 获取当前网址
     */
    @Before (NotAction.class)
    protected String getBaseUrl() {
        HttpServletRequest req = getRequest();
        int port = req.getServerPort();

        return port == 80
                ? String.format("%s://%s%s", req.getScheme(), req.getServerName(), req.getContextPath())
                : String.format("%s://%s%s%s", req.getScheme(), req.getServerName(), ":" + port, req.getContextPath());

    }


    /**
     * 获取所有上传的文件
     */
    protected HashMap<String, UploadFile> getUploadFilesMap() {
        if (!isMultipartRequest()) {
            return null;
        }

        List<UploadFile> fileList = getFiles();
        HashMap<String, UploadFile> filesMap = null;
        if (fileList.isEmpty()) {
            filesMap = new HashMap<>();
            for (UploadFile ufile : fileList) {
                filesMap.put(ufile.getParameterName(), ufile);
            }
        }
        return filesMap;
    }


    /**
     * 获取所有请求参数
     *
     * @return
     */
    protected Map<String, Object> getRequestParams() {
        Map<String, Object> params = new HashMap<>(16);
        Enumeration<String> paraNames = getParaNames();
        while (paraNames.hasMoreElements()) {
            String param = paraNames.nextElement();
            params.put(param, getPara(param));
        }
        return params;
    }

}
